package median;

import java.io.File;
import java.util.Arrays;

import common.IMS_CSV_File;
import common.ImageMethods;

import jsr166y.ForkJoinPool;
import jsr166y.RecursiveAction;

public class ForkJoinFastMedian extends RecursiveAction {

	private static final long serialVersionUID = 1L;
	private double[][] source;
	private double[][] destination;
	private int startColumn;
	private int columnsToCompute;
	private int maskSize;

	public ForkJoinFastMedian(int maskSize, double[][] source, int startColumn, int columnsToCompute, double[][] destination) {
		this.source = source;
		this.destination = destination;
		this.startColumn = startColumn;
		this.columnsToCompute = columnsToCompute;
		this.maskSize = maskSize;
	}

	public static void filterMedian(int maskSize, double[][] sourceMap, int startColumn, int columnsToCompute,
			double[][] destinationMap) {

		int maskR = (maskSize - 1) / 2;
		int medianPos = ((maskSize * maskSize + 1) / 2) - 1; 
		int eC;

		double[] elements = new double[maskSize * maskSize];

		for (int x = 0; x < destinationMap.length; x++) {	
			for (int y = startColumn; y < startColumn + columnsToCompute; y++) {
				eC = 0;
				for (int mx = maskR * -1; mx <= maskR; mx++) {
					for (int my = maskR * -1; my <= maskR; my++) {
						try {
							elements[eC] = sourceMap[x + mx][y + my];
						} catch (IndexOutOfBoundsException e) {
							elements[eC] = 0;
						}
						eC++;
					}
				}
				Arrays.sort(elements);
				destinationMap[x][y] = elements[medianPos];
				// overwrite spectra 1-3
				 if (y <= 3) {
					 destinationMap[x][y] = sourceMap[x][y];
				 }

			}
		}
	}

	protected void computeDirectly() {
		filterMedian(maskSize, source, startColumn, columnsToCompute, destination);
	}

	protected static int sThreshold = 11;

	@Override
	protected void compute() {
		if (columnsToCompute < sThreshold) {
			computeDirectly();
			return;
		}

		int split = columnsToCompute / 2;

		invokeAll(new ForkJoinFastMedian(maskSize,source, startColumn, split, destination), new ForkJoinFastMedian(maskSize,source,
				startColumn + split, columnsToCompute - split, destination));

	}

	public static void main(String[] args) throws Exception {
		IMS_CSV_File imsFile = new IMS_CSV_File(new File("E:/_IPHEx CBF/ims_files/NI24_0909171332_ims.csv"));
		double[][] sourceMap = imsFile.getMap();
		
		ForkJoinFastMedian.forkJoinFastMedian(sourceMap, 5);
		ImageMethods.filterMedian(sourceMap, 5);

	}

	public static double[][] forkJoinFastMedian(double[][] sourceMap,int maskSize) {
		long startTime = System.currentTimeMillis();
		
		int xDim = sourceMap.length;
		int yDim = sourceMap[0].length;
		double[][] destinationMap = new double[xDim][yDim];
		
		ForkJoinFastMedian forkJoinFastMedian = new ForkJoinFastMedian(maskSize,sourceMap, 0, yDim, destinationMap);
		ForkJoinPool pool = new ForkJoinPool();
		
		pool.invoke(forkJoinFastMedian);
		long endTime = System.currentTimeMillis();

		System.out.println("ForkJoinFastMedian took " + (endTime - startTime) + " milliseconds.");
		return(destinationMap);
	}

}
